require 'webrick/htmlutils'
require 'webrick/httputils'
require 'webrick/httpstatus'
require 'webrick/httpservlet'

class UPnP::Service::HTTPMythHandler < WEBrick::HTTPServlet::AbstractServlet
  Test_file = '/mnt/audiovideo/Video/test_myth.mpg'

  def create_instance
    super
      
    @log = File.new('/mnt/audiovideo/upnp.log', 'w')
  end
  
  def do_GET(req, res)
    @local_path = Test_file
    st = File::stat(@local_path)
    mtime = st.mtime

    @log.print "------------\n#{req.request_uri}\n  #{req.raw_header.join("  ")}"
    
    begin 
    if req['range'] 
      make_partial_content(req, res, @local_path, st.size)
      raise WEBrick::HTTPStatus::PartialContent
    else
      mtype = WEBrick::HTTPUtils::mime_type(@local_path, WEBrick::HTTPUtils::DefaultMimeTypes)

      res['content-type'] = mtype
      res['content-length'] = st.size
      res['last-modified'] = mtime.httpdate
      res.body = open(@local_path, "rb")
    end
    ensure
      @log.print "---\n#{res.status} - sent: #{res.sent_size}\n"
      res.header.to_a.each do |a| 
        @log.print "  #{a.join(": ")}\n"
      end
    end
    
  end

  def not_modified?(req, res, mtime, etag)
    if ir = req['if-range']
      begin
        if Time.httpdate(ir) >= mtime
          return true
        end
      rescue
        if WEBrick::HTTPUtils::split_header_value(ir).member?(res['etag'])
          return true
        end
      end
    end

    if (ims = req['if-modified-since']) && Time.parse(ims) >= mtime
      return true
    end

    if (inm = req['if-none-match']) &&
      WEBrick::HTTPUtils::split_header_value(inm).member?(res['etag'])
      return true
    end

    return false
  end

  def make_partial_content(req, res, filename, filesize)
    mtype = WEBrick::HTTPUtils::mime_type(@local_path, WEBrick::HTTPUtils::DefaultMimeTypes)

    unless ranges = WEBrick::HTTPUtils::parse_range_header(req['range'])
      raise WEBrick::HTTPUtils::BadRequest,
        "Unrecognized range-spec: \"#{req['range']}\""
    end
    open(filename, "rb"){|io|
      if ranges.size > 1
        time = Time.now
        boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
        body = ''
        ranges.each{|range|
          first, last = prepare_range(range, filesize)
          next if first < 0
          io.pos = first
          content = io.read(last-first+1)
          body << "--" << boundary << CRLF
          body << "Content-Type: #{mtype}" << CRLF
          body << "Content-Range: #{first}-#{last}/#{filesize}" << CRLF
          body << CRLF
          body << content
          body << CRLF
        }
        raise WEBrick::HTTPStatus::RequestRangeNotSatisfiable if body.empty?
        body << "--" << boundary << "--" << CRLF
        res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
        res.body = body
      elsif range = ranges[0]
        first, last = prepare_range(range, filesize)
        raise WEBrick::HTTPStatus::RequestRangeNotSatisfiable if first < 0
        if last == filesize - 1
          content = io.dup
          content.pos = first
        else
          io.pos = first
          content = io.read(last-first+1)
        end
        res['content-type'] = mtype
        res['content-range'] = "#{first}-#{last}/#{filesize}"
        res['content-length'] = last - first + 1
        res.body = content
      else
        raise WEBrick::HTTPStatus::BadRequest
      end
    }
  end

  def prepare_range(range, filesize)
    first = range.first < 0 ? filesize + range.first : range.first
    return -1, -1 if first < 0 || first >= filesize
    last = range.last < 0 ? filesize + range.last : range.last
    last = filesize - 1 if last >= filesize
    return first, last
  end
end
